package com.atguigu.yygh.hosp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.yygh.cmn.client.DictFeignClient;
import com.atguigu.yygh.common.exception.YyghException;
import com.atguigu.yygh.enums.DictEnum;
import com.atguigu.yygh.hosp.dao.HospitalRepository;
import com.atguigu.yygh.hosp.service.HospitalService;
import com.atguigu.yygh.model.hosp.Hospital;
import com.atguigu.yygh.vo.hosp.HospitalQueryVo;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author 孔德成
 * @slogan 致敬大师，致敬未来的你
 * @date 2021/9/3 9:55 上午
 * @desc
 */
@Service
public class HospitalServiceImpl implements HospitalService {
    private final DictFeignClient dictFeignClient;
    private final HospitalRepository hospitalRepository;


    public HospitalServiceImpl(DictFeignClient dictFeignClient, HospitalRepository hospitalRepository) {
        this.dictFeignClient = dictFeignClient;
        this.hospitalRepository = hospitalRepository;
    }

    @Override
    public void save(Map<String, Object> paramMap) {
        // 1. 将 map 转为 json 字符串，再将 json 字符串转为 bean 对象
        Hospital hospitalSave = JSONObject.parseObject(JSONObject.toJSONString(paramMap), Hospital.class);
        // 2. 根据医院编号查询医院信息
        Hospital hospitalQuery = hospitalRepository.findHospitalByHoscode(hospitalSave.getHoscode());
        // 3. 如果医院不存在，说明是第一次上传，需要将医院状态设置为锁定，待管理员审核
        if (ObjectUtil.isNull(hospitalQuery)) {
            // 初始化医院的其他信息：状态，逻辑删除字段，创建时间，更新时间，
            // 0 锁定；1 正常
            hospitalSave.setStatus(0);
            // 0 未删除；1 删除
            hospitalSave.setIsDeleted(0);
            hospitalSave.setCreateTime(new Date());
            hospitalSave.setUpdateTime(hospitalSave.getCreateTime());
        } else {
            // 医院存在，使用已存在信息填充其他空字段，执行更新操作
            hospitalSave.setId(hospitalQuery.getId());
            hospitalSave.setStatus(hospitalQuery.getStatus());
            hospitalSave.setIsDeleted(hospitalQuery.getIsDeleted());
            hospitalSave.setCreateTime(hospitalSave.getCreateTime());
            hospitalSave.setUpdateTime(new Date());
        }
        // 4. 保存（插入MongoDB）
        hospitalRepository.save(hospitalSave);
    }

    /**
     * mongodb 分页条件查询流程
     * 1. 创建 Pageable 分页条件
     * 1.1 创建排序规则 Sort.by
     * 1.2 封装排序规则，分页参数 PageRequest.of
     * 2. 创建 Example 查询条件
     * 2.1 创建匹配器 ExampleMatcher.matching()，指定如何使用条件
     * 2.2 使用 Example.of 封装实体类查询条件Bean和匹配器
     * 3. 使用 findAll(example, pageable) 查询
     *
     * @param page            当前页
     * @param limit           页面大小
     * @param hospitalQueryVo 条件查询对象
     * @return
     */
    @Override
    public Page<Hospital> selectPage(Integer page, Integer limit, HospitalQueryVo hospitalQueryVo) {
        // 参数校验
        if (ObjectUtil.isNull(page)) {
            page = 1;
        }
        if (ObjectUtil.isNull(limit)) {
            limit = 10;
        }

        // 根据创建时间降序排序
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        // mongodb 0 为第一页
        PageRequest pageOf = PageRequest.of(page - 1, limit, sort);

        // 创建匹配器，修改字符串匹配方式为模糊查询，忽略大小写
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
                .withIgnoreCase(true);

        // 创建查询条件
        Hospital hospital = BeanUtil.toBean(hospitalQueryVo, Hospital.class);
        Example<Hospital> exampleOf = Example.of(hospital, matcher);
        Page<Hospital> all = hospitalRepository.findAll(exampleOf, pageOf);
        all.getContent().forEach(this::packHospital);
        return all;
    }

    /**
     * 封装数据字典数据
     *
     * @param item
     */
    private void packHospital(Hospital item) {
        // 医院等级
        String hostype = dictFeignClient.getName(DictEnum.HOSTYPE.getDictCode(), item.getHostype());
        // 省
        String province = dictFeignClient.getName(null, item.getProvinceCode());
        // 市
        String city = dictFeignClient.getName(null, item.getCityCode());
        // 区
        String district = dictFeignClient.getName(null, item.getDistrictCode());
        // 使用额外参数封装数据字典数据
        item.getParam().put("hostypeString", hostype);
        item.getParam().put("fullAddress", province + city + district + item.getAddress());
    }

    @Override
    public Hospital getByHoscode(String hoscode) {
        return hospitalRepository.findHospitalByHoscode(hoscode);
    }

    @Override
    public void updateStatus(String id, Integer status) {

        // 出于程序健壮性考虑增加此检查
        if (!Arrays.asList(0, 1).contains(status)) {
            throw new YyghException(20001, "非法参数");
        }
        // 调用dao修改 status 即可
        Optional<Hospital> byId = hospitalRepository.findById(id);
        if (byId.isPresent()) {
            Hospital hospital = byId.get();
            hospital.setStatus(status);
            hospital.setUpdateTime(new Date());
            hospitalRepository.save(hospital);
        } else {
            throw new YyghException(20001, "医院不存在");
        }


    }

    @Override
    public Hospital show(String id) {
        // 避免返回 null
        Hospital hospital = new Hospital();
        Optional<Hospital> byId = hospitalRepository.findById(id);
        if (byId.isPresent()) {
            hospital = byId.get();

        }
        return hospital;
    }

    @Override
    public String getHospName(String hoscode) {
        Hospital hospitalByHoscode = hospitalRepository.findHospitalByHoscode(hoscode);
        return hospitalByHoscode.getHosname();
    }

    @Override
    public List<Hospital> selectHospPage(HospitalQueryVo hospitalQueryVo) {
        Hospital hospital = BeanUtil.toBean(hospitalQueryVo, Hospital.class);

        // 创建匹配器，修改字符串匹配方式为模糊查询，忽略大小写
        // 医院名称有模糊查询的需求
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
                .withIgnoreCase(true);
        Example<Hospital> of = Example.of(hospital, matcher);
        List<Hospital> all = hospitalRepository.findAll(of);
        // 封装医院等级
        all.forEach(this::packHospital);
        return all;
    }

    @Override
    public List<Hospital> findByHosname(String hosname) {
        return hospitalRepository.findHospitalByHosnameLike(hosname);
    }

    @Override
    public Map<String, Object> item(String hoscode) {
        Hospital hospital = hospitalRepository.findHospitalByHoscode(hoscode);
        // 封装数据字典信息
        packHospital(hospital);
        // 将医院详情信息分为基本信息和排班信息分开返回
        HashMap<String, Object> map = new HashMap<>(2);
        map.put("hospital", hospital);
        map.put("bookingRule", hospital.getBookingRule());
        // 避免重复返回数据
        hospital.setBookingRule(null);
        return map;

    }
}
